package readbook;

import com.alibaba.fastjson.JSON;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * nio 练习demo
 *
 * @author zhuqiang
 */
public class NioDemo {
    @Test
    public void fun_path() {
        Path path = Paths.get("F:\\技术文档\\pdf");
        System.out.println(path.toAbsolutePath());
        System.out.println(path.toFile().exists());
        System.out.println(path.getNameCount());
        // TWR 自动关闭流
        try (
                //可以过滤到指定的文件
                DirectoryStream<Path> paths = Files.newDirectoryStream(path, "Java*");
        ) {
            for (Path path1 : paths) {
                System.out.println(path1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void fun_ml() {
        Path path = Paths.get("F:\\");
        try {
            //给定一个对象FileVisitor，能帮你遍历到 给定的path下的所有文件
            Path fileTree = Files.walkFileTree(path, new MyFileVisitor());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class MyFileVisitor extends SimpleFileVisitor<Path> {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            System.out.println(file.getFileName());
            System.out.println(JSON.toJSONString(attrs));
            return super.visitFile(file, attrs);
        }
    }

    @Test
    public void fun_files() throws IOException {
        Path path = Paths.get("F:\\技术文档\\pdf\\demo");
        // 在linux 上面创建文件目录,加上权限
/*        Files.createDirectories(path,
                PosixFilePermissions.asFileAttribute(
                        PosixFilePermissions.fromString("rw-rw-rw")));*/
        Files.createDirectories(path); //对于目录，不存在的直接创建，存在的会创建失败，但是api已经将异常过滤掉了
        Path file = Paths.get(path.toString(), "text.txt");
//        Files.createFile(file); //如果已经存在该文件，将会抛出异常

        Path file2 = Paths.get(path.toString(), "text2.txt");
//        Files.copy(file, file2); //文件复制
        Path file3 = Paths.get(path.toString(), "text3.txt");
//        Files.move(file2,file3); //文件移动
        Files.delete(file3); //文件删除
    }
    @Test
    public void fun_file_attr() throws IOException {
        Path path = Paths.get("F:\\技术文档\\pdf\\demo");
        System.out.println(Files.getLastModifiedTime(path)); //获取最后一次修改时间
        System.out.println(Files.readAttributes(path,"*")); //读取所有的属性
    }

    @Test
    public void fun_file_read(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        if(!path.toFile().exists()){
            System.out.println("文件不存在");
        }

        try(
                //文件编码一定要正确，否则将读取异常
                BufferedReader bufferedReader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
            ){
            String line = null;
            while ((line = bufferedReader.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void fun_file_write(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        try(
              //默认是没有文件则创建一个新文件，有文件则直接覆盖
//            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8);
            //该模式是没有文件则报错。
//            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8,StandardOpenOption.APPEND);
              //通过打开模式可以快速的帮我们进行一些逻辑的设定，比如下面的组合，文件不存在则先创建
            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8,
                    StandardOpenOption.APPEND,
                    StandardOpenOption.CREATE);
        ){
            bufferedWriter.write("追加文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void fun_file_simpl_read() throws IOException {
        // 简化读取
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        List<String> strings = Files.readAllLines(path, StandardCharsets.UTF_8);
        System.out.println(Arrays.toString(strings.toArray()));
    }

    @Test
    public void fun_watchservice() {
        try (
                WatchService watchService = FileSystems.getDefault().newWatchService();
        ) {
            Path path = Paths.get("E:\\学习\\"); //只能对一个目录下的文件进行监控，有点类似zookpooer的节奏
            // 在该路径上注册
            WatchKey watchKey = path.register(watchService,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE); //对修改进行监控
            boolean flag = true; //用于跳出循环
            while(flag){
                WatchKey take = watchService.take(); //如果有事

                // 件触发，将会被放入服务队列中，等待处理
//                List<WatchEvent<?>> watchEvents = watchKey.pollEvents(); //获取该key上的所有事件：其实没有太明白 这个WatchService 和 WatchKey的关系。所以下面的代码有点没有搞明白
                List<WatchEvent<?>> watchEvents = take.pollEvents();
                for (WatchEvent<?> watchEvent : watchEvents) {
                    if(watchEvent.kind() == StandardWatchEventKinds.ENTRY_MODIFY){
                        Object context = watchEvent.context(); //在windows中 该对象类型原型是私有的 WindowsPath类型，但是该类的实现接口也是path
                        Path file = (Path)context; //返回的是针对该目录的一个相对路径
                        Path child = path.resolve(file); // 不太看得懂英文说明：这里需要转换为绝对路径，这个是一个简便的转换
                        List<String> strings = Files.readAllLines(child, StandardCharsets.UTF_8);
                        System.out.println(Arrays.toString(strings.toArray()));
                    }
                }
                watchKey.reset(); //重置监控key
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void fun_channel(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        
        try (
                FileChannel fc = FileChannel.open(path, StandardOpenOption.READ);
                ){
            // fc.size 返回的是自己数，utf中一个汉字占三个字节
            int read = fc.read(buffer, fc.size() - 3); // 读取该文件最后的三个字节
            System.out.println(new String(buffer.array()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private abstract class A{
        public abstract void sy(Map<String,String> map) throws NumberFormatException;
    }
    private class B extends A {

        @Override
        public void sy(Map<String,String> map) {

        }
    }

}
